package cn.edu.zju.om.data;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.LockMode;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.criterion.Criterion;



public class DAO<T, ID extends Serializable> {
	
	private Class<T> persistentClass;

	

	public DAO(Class<T> persistentClass) {
		this.persistentClass = persistentClass;
	}
	
	public static Session getSession() {
		Session session = (Session) DAO.session.get();
		
		if (session == null) {
			session = sessionFactory.openSession();
			DAO.session.set(session);
		}
		
		return session;
	}
	
	
	
	private static final ThreadLocal<Session> session = new ThreadLocal<Session>();
	
	private static final SessionFactory sessionFactory =
		new AnnotationConfiguration().configure().buildSessionFactory();
	
    public Class<T> getPersistentClass() {
        return persistentClass;
    }

	
    public T findById(ID id, boolean lock) {
        T entity;
        if (lock)
            entity = (T) getSession().load(getPersistentClass(), id, LockMode.UPGRADE);
        else
            entity = (T) getSession().load(getPersistentClass(), id);

        return entity;
    }
    
    public T findByColumn(String coloumName, String value) {
    	begin();
    	T entity;
    	System.out.println(String.format("from %s where %s = %s",
    			getPersistentClass().getSimpleName(),
    			coloumName,
    			value));
    	Query query = getSession().createQuery(String.format("from %s where %s = %s",
    			getPersistentClass().getSimpleName(),
    			coloumName,
    			value));
    	entity = (T) query.uniqueResult();
    	commit();
    	
    	return entity;
    }
    
    public T makePersistent(T entity) {
    	begin();
        getSession().saveOrUpdate(entity);
        commit();
        return entity;
    }

    public List<T> findAll() {
        return findByCriteria();
    }

    protected List<T> findByCriteria(Criterion... criterion) {
        Criteria crit = getSession().createCriteria(getPersistentClass());
        for (Criterion c : criterion) {
            crit.add(c);
        }
        return crit.list();
   }
    
    protected void begin() {
		getSession().beginTransaction();
	}
    
    protected void commit() {
		getSession().getTransaction().commit();
	}



}